package state;

import java.util.Vector;

import state.component.BottomBar;
import state.component.Component;
import state.component.GameMenu;
import state.component.GameScrollBar;
import state.component.TouchPad;
import state.util.GameColor;

public class Manager {
  private Sprite baseSprite = null;
  private Sprite root = null;
  private Sprite last = null;
  private int backGroundColor = GameColor.WHITE_CODE;
  private GameForm parent = null;
  private Pointer pointer = null;
  private boolean isUseMouseMoveEvent = false;
  private GameImage backgroundImage = null;
  private Vector scrolls = null;

  private BottomBar bottomBar = null;
  private TouchPad touchPad = null;
  private boolean fillBackgroundColor = true;

  private boolean isContinueEvent = false;

  public Manager(GameForm parent1) {
    this.parent = parent1;
    baseSprite = new Sprite(null, this, 0, 0, GameConstants.TOP_LEFT_ANCHOR);
    baseSprite.setSize(GameConstants.SCREEN_WIDTH, GameConstants.SCREEN_HEIGHT);
    DrawListener3 drawListener3 = new DrawListener3();
    baseSprite.setDrawListener(drawListener3);
    root = baseSprite;
    last = root;
  }
  
  class DrawListener3 implements DrawListener {
    public void paint(Sprite source, Graphics g) {
      Manager.this.parent.draw(g);
    }
  }
  
  public void setFillBackgroundColor(boolean isFillBackgroundColor) {
    this.fillBackgroundColor = isFillBackgroundColor;
  }
  
  public boolean isFillBackgroundColor() {
    return fillBackgroundColor;
  }

  public void enableTouchPad() {
    touchPad = new TouchPad(this);
  }

  public void disableTouchPad() {
    if (touchPad != null) {
      touchPad.detroy();
      touchPad = null;
    }
  }

  public void stopEvent() {
    isContinueEvent = false;
  }

  /**
   * Sử dụng pointer trong State hiện tại
   */
  public void enablePointer() {
    if (pointer == null) {
      pointer = new Pointer(this);
      if (isUseMouseMoveEvent) {
        pointer.useMouseMoveEvent();
      }
    }
  }

  /**
   * Hủy sử dụng pointer
   */
  public void disablePointer() {
    if (pointer != null) {
      remove(pointer);
      pointer.detroy();
      pointer = null;
    }
  }

  public Sprite getBaseSprite() {
    return baseSprite;
  }

  /**
   * Lấy pointer đang xử dụng của manager
   * 
   * @return Pointer đang xử dụng của manager, trả về null nếu không có pointer nào được xử dụng
   */
  public Pointer getPointer() {
    return pointer;
  }

  private Clip reuseClip = new Clip(0, 0, 0, 0);

  /**
   * Tự động cập nhật tất cả các thay đổi của các Sprite trong State lên Graphic.
   * Phương thức này sẽ tự động cập nhật Graphic nên màn hình nếu tham số tự động cập nhật màn hình isAutoFlushGraphic được set là true
   */
  public void updateFullScreen() {
    if (!parent.isRunning) {
      return;
    }

    Graphics g = getGraphics();
    if (g == null) {
      return;
    }

    Clip.getClip1(g, reuseClip);
    reuseClip.clipRect(g, parent._realX, parent._realY, parent._width, parent._height);
    if (fillBackgroundColor) {
      g.setColor(backGroundColor);
      g.fillRect(parent._realX, parent._realY, parent._width, parent._height);
    }

    if (backgroundImage != null) {
      g.drawImage(backgroundImage, parent._realX, parent._realY, GameConstants.TOP_LEFT_ANCHOR);
    }

    if (root != null) {
      Sprite current = root;
      while (current != null) {
        g.clipRect(current.getRealX(), current.getRealY(), current.getWidth(), current.getHeight());
        current.paint(g);
        current = current.next;
        reuseClip.applyClip(g);
      }
    }
    reuseClip.applyClip(g);

    if (scrolls != null) {
      for (int i = 0; i < scrolls.size(); i++) {
        GameScrollBar scrollBar = (GameScrollBar) scrolls.elementAt(i);
        scrollBar.reset();
      }
    }

    if (bottomBar != null) {
      bottomBar.draw(g);
    }

    if (touchPad != null) {
      touchPad.paint(g);
    }
  }

  public void addScrollBar(GameScrollBar scrollBar) {
    if (scrolls == null) {
      scrolls = new Vector();
    }
    scrolls.addElement(scrollBar);
  }

  public BottomBar getBottomBar() {
    return bottomBar;
  }

  public void setBottomBar(BottomBar bottomBar1) {
    this.bottomBar = bottomBar1;
  }

  public void setBackgroundImage(GameImage backgroundImage1) {
    this.backgroundImage = backgroundImage1;
  }

  /**
   * Lấy Graphic đang xử dụng hiện tại
   * 
   * @return Graphic đang xử dụng
   */
  public Graphics getGraphics() {
    return GameGlobal.systemCanvas.getGraphic();
  }

  /**
   * Thiết lập mầu nền cho State
   * 
   * @param color - Mầu nền
   */
  public void setBackGroundColor(int color) {
    backGroundColor = color;
  }

  /**
   * Lấy State hiện tại của manager này
   * 
   * @return State hiện tại của manager
   */
  public GameForm getParent() {
    return parent;
  }

  public final void setFocus(Component component) {
    if (root != null) {
      Sprite current = root;
      while (current != null) {
        current.setFocused(false);
        current = current.next;
      }
    }
    component.setFocused(true);
  }

  public final void doKeyPressed(int keyCode) {
    isContinueEvent = true;

    if (isContinueEvent && bottomBar != null) {
      bottomBar.keyPressed(bottomBar, keyCode);

      if (isContinueEvent && bottomBar.getLeftMenu() != null) {
        GameMenu leftMenu = bottomBar.getLeftMenu();
        leftMenu.keyPressed(leftMenu, keyCode);
      }

      if (isContinueEvent && bottomBar.getRightMenu() != null) {
        GameMenu rightMenu = bottomBar.getRightMenu();
        rightMenu.keyPressed(rightMenu, keyCode);
      }
    }

    if (isContinueEvent && root != null) {
      Sprite current = root;
      while (isContinueEvent && current != null) {
        if (current.isVisible() && current._keyListener != null) {
          current._keyListener.keyPressed(current, keyCode);
        }
        current = current.next;
      }
    }
  }

  public final void doKeyReleased(int keyCode) {
    isContinueEvent = true;

    if (isContinueEvent && bottomBar != null) {
      bottomBar.keyReleased(bottomBar, keyCode);

      if (isContinueEvent && bottomBar.getLeftMenu() != null) {
        GameMenu leftMenu = bottomBar.getLeftMenu();
        leftMenu.keyReleased(leftMenu, keyCode);
      }

      if (isContinueEvent && bottomBar.getRightMenu() != null) {
        GameMenu rightMenu = bottomBar.getRightMenu();
        rightMenu.keyReleased(rightMenu, keyCode);
      }
    }

    if (isContinueEvent && root != null) {
      Sprite current = root;
      while (isContinueEvent && current != null) {
        if (current.isVisible() && current._keyListener != null) {
          current._keyListener.keyReleased(current, keyCode);
        }
        current = current.next;
      }
    }
  }

  public final void doKeyRepeated(int keyCode) {
    isContinueEvent = true;

    if (isContinueEvent && bottomBar != null) {
      bottomBar.keyRepeated(bottomBar, keyCode);
      if (isContinueEvent && bottomBar.getLeftMenu() != null) {
        GameMenu leftMenu = bottomBar.getLeftMenu();
        leftMenu.keyRepeated(leftMenu, keyCode);
      }

      if (isContinueEvent && bottomBar.getRightMenu() != null) {
        GameMenu rightMenu = bottomBar.getRightMenu();
        rightMenu.keyRepeated(rightMenu, keyCode);
      }
    }

    if (isContinueEvent && root != null) {
      Sprite current = root;
      while (isContinueEvent && current != null) {
        if (current.isVisible() && current._keyListener != null) {
          current._keyListener.keyRepeated(current, keyCode);
        }
        current = current.next;
      }
    }
  }

  public final void doMousePressed(int x, int y) {
    isContinueEvent = true;
    if (isContinueEvent && bottomBar != null) {
      if (isContinueEvent && bottomBar._mouseListener != null && bottomBar.contains(x, y)) {
        bottomBar._mouseListener.mousePressed(bottomBar, x, y);
      }

      if (isContinueEvent && bottomBar.getLeftMenu() != null) {
        GameMenu leftMenu = bottomBar.getLeftMenu();
        if (leftMenu._mouseListener != null) {
          leftMenu._mouseListener.mousePressed(leftMenu, x, y);
        }
      }

      if (isContinueEvent && bottomBar.getRightMenu() != null) {
        GameMenu rightMenu = bottomBar.getRightMenu();
        if (rightMenu._mouseListener != null) {
          rightMenu._mouseListener.mousePressed(rightMenu, x, y);
        }
      }
    }

    if (isContinueEvent && root != null) {
      Sprite current = last;
      while (isContinueEvent && current != null) {
        if (isContinueEvent && current.isVisible() && (current != pointer) && current.checkCollides(x, y)) {
          if (current._mouseListener != null) {
            current._mouseListener.mousePressed(current, x, y);
          }
          break;
        }
        current = current.previous;
      }
    }
  }

  public final void doMouseReleased(int x, int y) {
    isContinueEvent = true;

    if (isContinueEvent && bottomBar != null) {
      if (isContinueEvent && bottomBar._mouseListener != null && bottomBar.contains(x, y)) {
        bottomBar._mouseListener.mouseReleased(bottomBar, x, y);
      }

      if (isContinueEvent && bottomBar.getLeftMenu() != null) {
        GameMenu leftMenu = bottomBar.getLeftMenu();
        if (leftMenu._mouseListener != null) {
          leftMenu._mouseListener.mouseReleased(leftMenu, x, y);
        }
      }

      if (isContinueEvent && bottomBar.getRightMenu() != null) {
        GameMenu rightMenu = bottomBar.getRightMenu();
        if (rightMenu._mouseListener != null) {
          rightMenu._mouseListener.mouseReleased(rightMenu, x, y);
        }
      }
    }

    if (isContinueEvent && root != null) {
      Sprite current = last;
      while (isContinueEvent && current != null) {
        if (isContinueEvent && current.isVisible() && (current != pointer) && current.checkCollides(x, y)) {
          if (current._mouseListener != null) {
            current._mouseListener.mouseReleased(current, x, y);
          }
          break;
        }
        current = current.previous;
      }
    }
  }

  public final void doMouseMoved(int x, int y) {
    isContinueEvent = true;

    if (isContinueEvent && root != null) {
      Sprite current = last;
      while (isContinueEvent && current != null) {
        if (isContinueEvent && current.isVisible() && (current != pointer) && current.checkCollides(x, y)) {
          if (current._mouseMoveListener != null) {
            pointer.setCurrentMoveOnItem(current);
            current._mouseMoveListener.mouseMoved(current, x, y);
          }
          break;
        }
        current = current.previous;
      }
    }

    if (isContinueEvent && bottomBar != null) {
      if (isContinueEvent && bottomBar._mouseMoveListener != null && bottomBar.contains(x, y)) {
        bottomBar._mouseMoveListener.mouseMoved(bottomBar, x, y);
      }

      if (isContinueEvent && bottomBar.getLeftMenu() != null) {
        GameMenu leftMenu = bottomBar.getLeftMenu();
        if (leftMenu._mouseMoveListener != null) {
          leftMenu._mouseMoveListener.mouseMoved(leftMenu, x, y);
        }
      }

      if (isContinueEvent && bottomBar.getRightMenu() != null) {
        GameMenu rightMenu = bottomBar.getRightMenu();
        if (rightMenu._mouseMoveListener != null) {
          rightMenu._mouseMoveListener.mouseMoved(rightMenu, x, y);
        }
      }
    }
  }

  public final void doPointerDragged(int x, int y) {
    isContinueEvent = true;
    if (bottomBar != null) {
      if (isContinueEvent && bottomBar._touchScreenListener != null && bottomBar.contains(x, y)) {
        bottomBar._touchScreenListener.pointerDragged(bottomBar, x, y);
      }

      if (isContinueEvent && bottomBar.getLeftMenu() != null) {
        GameMenu leftMenu = bottomBar.getLeftMenu();
        if (leftMenu._touchScreenListener != null) {
          leftMenu._touchScreenListener.pointerDragged(leftMenu, x, y);
        }
      }

      if (isContinueEvent && bottomBar.getRightMenu() != null) {
        GameMenu rightMenu = bottomBar.getRightMenu();
        if (rightMenu._touchScreenListener != null) {
          rightMenu._touchScreenListener.pointerDragged(rightMenu, x, y);
        }
      }
    }

    if (isContinueEvent && touchPad != null) {
      touchPad._touchScreenListener.pointerDragged(touchPad, x, y);
    }

    if (root != null) {
      Sprite current = root;
      while (isContinueEvent && current != null) {
        if (current.isVisible() && (current._touchScreenListener != null) && current.contains(x, y)) {
          current._touchScreenListener.pointerDragged(current, x, y);
        }
        current = current.next;
      }
    }
  }

  public final void doPointerPressed(int x, int y) {
    isContinueEvent = true;
    if (bottomBar != null) {
      if (isContinueEvent && bottomBar._touchScreenListener != null && bottomBar.contains(x, y)) {
        bottomBar._touchScreenListener.pointerPressed(bottomBar, x, y);
      }

      if (isContinueEvent && bottomBar.getLeftMenu() != null) {
        GameMenu leftMenu = bottomBar.getLeftMenu();
        if (leftMenu._touchScreenListener != null) {
          leftMenu._touchScreenListener.pointerPressed(leftMenu, x, y);
        }
      }

      if (isContinueEvent && bottomBar.getRightMenu() != null) {
        GameMenu rightMenu = bottomBar.getRightMenu();
        if (rightMenu._touchScreenListener != null) {
          rightMenu._touchScreenListener.pointerPressed(rightMenu, x, y);
        }
      }
    }

    if (isContinueEvent && touchPad != null) {
      touchPad._touchScreenListener.pointerPressed(touchPad, x, y);
    }

    if (root != null) {
      Sprite current = root;
      while (isContinueEvent && current != null) {
        if (current.isVisible() && (current._touchScreenListener != null) && current.contains(x, y)) {
          current._touchScreenListener.pointerPressed(current, x, y);
        }
        current = current.next;
      }
    }
  }

  public final void doPointerReleased(int x, int y) {
    isContinueEvent = true;
    if (bottomBar != null) {
      if (isContinueEvent && bottomBar._touchScreenListener != null && bottomBar.contains(x, y)) {
        bottomBar._touchScreenListener.pointerReleased(bottomBar, x, y);
      }

      if (isContinueEvent && bottomBar.getLeftMenu() != null) {
        GameMenu leftMenu = bottomBar.getLeftMenu();
        if (leftMenu._touchScreenListener != null) {
          leftMenu._touchScreenListener.pointerReleased(leftMenu, x, y);
        }
      }

      if (isContinueEvent && bottomBar.getRightMenu() != null) {
        GameMenu rightMenu = bottomBar.getRightMenu();
        if (rightMenu._touchScreenListener != null) {
          rightMenu._touchScreenListener.pointerReleased(rightMenu, x, y);
        }
      }
    }

    if (isContinueEvent && touchPad != null) {
      touchPad._touchScreenListener.pointerReleased(touchPad, x, y);
    }

    if (root != null) {
      Sprite current = root;
      while (isContinueEvent && current != null) {
        if (current.isVisible() && (current._touchScreenListener != null) && current.contains(x, y)) {
          current._touchScreenListener.pointerReleased(current, x, y);
        }
        current = current.next;
      }
    }
  }

  public final void useMouseMoveEvent() {
    isUseMouseMoveEvent = true;
    if (pointer != null) {
      pointer.useMouseMoveEvent();
    }
  }

  /**
   * Thêm 1 LinkedSprite vào danh sách quản lý của manager.
   * Cần lưu ý là LinkedSprite thêm vào sau sẽ được vẽ phía trên các LinkedSprite thêm vào trước đó.
   * 
   * @param c - LinkedSprite thêm vào danh sách quản lý
   */
  public void append(Sprite c) {
    if (c._manager == this) {
      return;
    }

    if (root == null) {
      root = c;
      last = root;
    } else {
      last.next = c;
      c.previous = last;
      last = c;
    }
    c._manager = this;

    if (c._mouseMoveListener != null) {
      useMouseMoveEvent();
    }
  }

  public void insertToHead(Sprite c) {
    if (c._manager == this) {
      return;
    }

    if (root == null) {
      root = c;
      last = root;
    } else {
      c.next = root;
      root.previous = c;
      root = c;
    }
    c._manager = this;

    if (c._mouseMoveListener != null) {
      useMouseMoveEvent();
    }
  }

  /**
   * Thêm 1 LinkedSprite vào danh sách quản lý của manager ở 1 vị trí sau LinkSprite source trong danh sách
   * Cần lưu ý là các LinkedSprite được vẽ theo thứ tự index, LinkedSprite có index lớn hơn sẽ sẽ được vẽ phía trên.
   * 
   * @param newSprite - LinkedSprite thêm vào danh sách quản lý
   * @param source - LinkedSprite để xác định thêm newSprite vào vị trí phía sau
   */
  public void insertAfter(Sprite newSprite, Sprite source) {
    if (newSprite._manager == this) {
      return;
    }

    if (source._manager != this) {
      return;
    }

    newSprite._manager = this;
    if (source.next != null) {
      newSprite.next = source.next;
      newSprite.previous = source;
      source.next.previous = newSprite;
      source.next = newSprite;
    } else {
      source.next = newSprite;
      newSprite.previous = source;
    }

    if (newSprite._mouseMoveListener != null) {
      useMouseMoveEvent();
    }
  }

  /**
   * Thêm 1 LinkedSprite vào danh sách quản lý của manager ở 1 vị trí trước LinkSprite source trong danh sách
   * Cần lưu ý là các LinkedSprite được vẽ theo thứ tự index, LinkedSprite có index lớn hơn sẽ sẽ được vẽ phía trên.
   * 
   * @param newSprite - LinkedSprite thêm vào danh sách quản lý
   * @param source - LinkedSprite để xác định thêm newSprite vào vị trí phía trước
   */
  public void insertBefore(Sprite newSprite, Sprite source) {
    if (newSprite._manager == this) {
      return;
    }

    if (source._manager != this) {
      return;
    }

    newSprite._manager = this;
    newSprite.previous = source.previous;
    newSprite.next = source;
    source.previous.next = newSprite;
    source.previous = newSprite;

    if (newSprite._mouseMoveListener != null) {
      useMouseMoveEvent();
    }
  }

  /**
   * Bỏ 1 LinkedSprite ra khỏi danh sách quản lý của manager.
   * Lưu ý là LinkedSprite đã được loại bỏ sẽ không được cập nhật hiển thị nữa
   * 
   * @param c - LinkedSprite cần bỏ ra khỏi danh sách quản lý
   */
  public void remove(Sprite c) {
    if ((c == null) || (c == baseSprite) || (c._manager != this)) {
      return;
    }

    if (root == c) {
      root = c.next;
    } else {
      c.previous.next = c.next;
    }

    if (last == c) {
      last = c.previous;
    } else {
      c.next.previous = c.previous;
    }

    c.previous = null;
    c.next = null;
    c._manager = null;
  }

  /**
   * Loại bỏ tất cả các LinkedSprite đang quản lý ra khỏi danh sách
   */
  public void removeAll() {
    if (pointer != null) {
      pointer.detroy();
      pointer = null;
    }
    isUseMouseMoveEvent = false;

    Sprite current = last;
    while (current != root) {
      current._manager = null;
      if (current.next != null) {
        current.next.previous = null;
        current.next = null;
      }
      current = current.previous;
    }
    if (root.next != null) {
      root.next.previous = null;
      root.next = null;
    }

    root = baseSprite;
    last = root;
  }

  /**
   * Loại bỏ và detroy tất cả các LinkedSprite hiện tại trong danh sách
   */
  public void detroyAll() {
    isUseMouseMoveEvent = false;
    backgroundImage = null;
    Sprite current = last;
    Sprite tmp;
    while (current != root) {
      tmp = current;
      current = current.previous;
      if (tmp.next != null) {
        tmp.next.previous = null;
        tmp.next = null;
      }

      if (tmp != baseSprite) {
        tmp.detroy();
      }
    }

    if (root != null) {
      if (root.next != null) {
        root.next.previous = null;
        root.next = null;
      }
    }

    root = baseSprite;
    last = root;
    pointer = null;
    scrolls = null;
  }
}
